#include "ProduceConsume.h"

// 初始化类静态成员
std::condition_variable ProduceConsume::m_variable;
std::mutex ProduceConsume::m_mutex;
std::list<int> ProduceConsume::m_dataList = list<int>();


ProduceConsume::ProduceConsume()
{
    m_runFlag = true;
}

void ProduceConsume::startThread()
{
    // 做函数指针使用
    std::function<void(void*)> thFunc;

    // 生产者线程
    thFunc = ProduceConsume::ThreadProducer;
    std::thread threadProduce = std::thread(thFunc, this);

    // 消费者线程
    thFunc = ProduceConsume::ThreadConsumer;
    std::thread threadConsume = std::thread(thFunc, this);

    threadProduce.join();
    threadConsume.join();
}

void ProduceConsume::ThreadProducer(void *arg)
{
    ProduceConsume *pThis = static_cast<ProduceConsume*>(arg);

    int count = 1 ;
    while (pThis->m_runFlag.load())
    {
        std::unique_lock<std::mutex> m_uniqueLock(m_mutex);
        m_dataList.push_back(count);
        m_uniqueLock.unlock();
        std::cout << "Producer: " << count << endl;

        // 唤醒
        m_variable.notify_all();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));        // 当前线程休眠时间, 毫秒计算

        count++;
        if ( count == 100 )
        {
            // 本身退出，并且通知消费线程一起退出
            pThis->m_runFlag.store(false);
            m_variable.notify_all();
        }
    }
    std::cout << "ThreadProducer Finish.\n";
}

void ProduceConsume::ThreadConsumer(void *arg)
{
    ProduceConsume *pThis = static_cast<ProduceConsume*>(arg);

    while(pThis->m_runFlag.load())
    {
        // 休眠等待消费
        std::unique_lock<std::mutex> m_uniqueLock(m_mutex);
        m_variable.wait(m_uniqueLock);

//        m_variable.wait(m_uniqueLock, []{
//            return m_dataList.size() > 0;                   //          即使是收到唤醒的信号后, 如果不满足lamba的结果，还是会阻塞
//        });

        std::cout << "Consume !!! size: " << m_dataList.size() << endl;
        if ( m_dataList.size() == 0 )
            continue;

        int num = m_dataList.back();
        m_dataList.pop_back();
        std::cout << "num: " << num << endl;
        std::cout << endl;
    }

    std::cout << "ThreadConsumer Finish.\n";
}
